package com.example.clone;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import android.content.Context;
import android.os.Handler;
import android.os.Handler.Callback;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;

import com.example.utils.Zmlib;

public class Server implements Callback {
	public static final int PORT = 8889;
	public static final int BUFFER_SIZE = 1024 * 16;
	private boolean isStop;
	private Context context;
	private ExecutorService pool;
	private Handler handler;

	public Server(Context context) {
		this.context = context;
		handler = new Handler(this);
	}

	private void shutdownAndAwaitTermination(ExecutorService pool) {
		pool.shutdown(); // Disable new tasks from being submitted
		try {
			// Wait a while for existing tasks to terminate
			if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
				pool.shutdownNow(); // Cancel currently executing tasks
				// Wait a while for tasks to respond to being cancelled
				if (!pool.awaitTermination(60, TimeUnit.SECONDS))
					Zmlib.toastLong(context, "Pool did not terminate");
			}
		} catch (InterruptedException ie) {
			// (Re-)Cancel if current thread also interrupted
			pool.shutdownNow();
			// Preserve interrupt status
			Thread.currentThread().interrupt();
		}
	}

	public void stopServer() {
		isStop = true;
		if (pool != null) {
			shutdownAndAwaitTermination(pool);
			pool = null;
		}
	}

	public void startServer() {
		isStop = false;
		pool = Executors.newCachedThreadPool();
		// UDP 响应服务器（查找服务器用）
		startUDP();
		// TCP 文件传送服务器
		startTCP();
	}

	private void log(Object o) {
		Log.e("zm Server", "" + o);

	}

	@Override
	public boolean handleMessage(Message msg) {
		switch (msg.what) {
		case 1:
			Zmlib.toast(context, msg.obj);
			break;

		default:
			return false;
		}
		return true;
	}

	private void startUDP() {
		pool.execute(new Runnable() {
			@Override
			public void run() {
				try {
					DatagramSocket ds = new DatagramSocket(PORT);
					ds.setSoTimeout(500);
					handler.obtainMessage(1, "UDP服务已启动").sendToTarget();
					String helloworld = "helloworld";
					byte[] data = new byte[helloworld.length()];
					DatagramPacket dp = new DatagramPacket(data, data.length);
					while (!isStop) {
						try {
							ds.receive(dp);
							String str = new String(dp.getData(), 0, dp
									.getLength());
							log(dp.getAddress().getHostAddress() + ":" + str);
							if (str.equals(helloworld)) {
								ds.send(dp);
								ds.send(dp);
								ds.send(dp);
								ds.send(dp); //多发几次，防止丢包
							}
						} catch (SocketTimeoutException e) {
						}
					}
					ds.close();
					handler.obtainMessage(1, "UDP服务已关闭").sendToTarget();

				} catch (IOException e) {
					e.printStackTrace();
					handler.obtainMessage(1, "UDP服务启动失败").sendToTarget();
				}
			}
		});
	}

	private void startTCP() {
		pool.execute(new Runnable() {
			public void run() {
				try {
					ServerSocket ss = new ServerSocket(PORT);
					ss.setSoTimeout(1000);
					handler.obtainMessage(1, "TCP服务已启动").sendToTarget();
					while (!isStop) {
						try {
							acceptClient(ss.accept());
						} catch (SocketTimeoutException e) {
						}
					}
					ss.close();
					handler.obtainMessage(1, "TCP服务已关闭").sendToTarget();
				} catch (IOException e) {
					e.printStackTrace();
					handler.obtainMessage(1, "TCP服务启动失败").sendToTarget();
				}
			}
		});
	}

	/**
	 * 通信协议：<br/>
	 * 请求：请求行为空字符串，返回当前apk 请求行为文件路径，返回指定路径<br/>
	 * <br/>
	 * 
	 * 响应：第一个返回数据为long类型，代表文件长度 之后返回文件内容，然后结束
	 */
	private void acceptClient(final Socket s) {
		pool.execute(new Runnable() {
			public void run() {
				InputStream in = null;
				try {
					int i = java.net.SocketOptions.SO_TIMEOUT;

					s.setSoTimeout(5000);
					log("ip:" + s.getInetAddress().getHostAddress());
					DataInputStream input = new DataInputStream(s
							.getInputStream());
					String path = input.readUTF();
					log(path);
					if (TextUtils.isEmpty(path)) {
						path = context.getPackageCodePath();
					}
					File f = new File(path);
					DataOutputStream out = new DataOutputStream(s
							.getOutputStream());
					out.writeLong(f.length());
					in = new FileInputStream(f);
					byte[] buf = new byte[BUFFER_SIZE];
					int len;
					while ((len = in.read(buf)) != -1) {
						out.write(buf, 0, len);
					}
				} catch (FileNotFoundException e) {
					
				} catch (IOException e) {
					e.printStackTrace();
				} finally {
					try {
						s.close();
					} catch (Exception e) {
					}
					try {
						in.close();
					} catch (Exception e) {
					}
				}
			};
		});

	}

}
